#include "sdio_sdcard.h"
#include "string.h"

/*
 * SD初始化的时候调用库函数HAL_SD_InitCard，这个函数内部有HAL_Delay，导致程序无法正常运行 
 */
SD_HandleTypeDef        SDCARD_Handler;     //SD卡句柄
HAL_SD_CardInfoTypeDef  SDCardInfo;         //SD卡信息结构体
DMA_HandleTypeDef SDTxDMAHandler,SDRxDMAHandler;    //SD卡DMA发送和接收句柄

//SD_ReadDisk/SD_WriteDisk函数专用buf,当这两个函数的数据缓存区地址不是4字节对齐的时候,
//需要用到该数组,确保数据缓存区地址是4字节对齐的.
__attribute__((align(4))) unsigned char SDIO_DATA_BUFFER[512];

//SD卡初始化
//返回值:0 初始化正确；其他值，初始化错误
unsigned char SD_Init(void)
{
    unsigned char SD_Error;
    //初始化时的时钟不能大于400KHZ 
    SDCARD_Handler.Instance=SDIO;
    SDCARD_Handler.Init.ClockEdge=SDIO_CLOCK_EDGE_RISING;          			//上升沿     
    SDCARD_Handler.Init.ClockBypass=SDIO_CLOCK_BYPASS_DISABLE;     			//不使用bypass模式，直接用HCLK进行分频得到SDIO_CK
    SDCARD_Handler.Init.ClockPowerSave=SDIO_CLOCK_POWER_SAVE_DISABLE;    	//空闲时不关闭时钟电源
    SDCARD_Handler.Init.BusWide=SDIO_BUS_WIDE_1B;                        	//1位数据线
    SDCARD_Handler.Init.HardwareFlowControl=SDIO_HARDWARE_FLOW_CONTROL_DISABLE;//关闭硬件流控
    SDCARD_Handler.Init.ClockDiv=SDIO_TRANSFER_CLK_DIV;            			//SD传输时钟频率最大25MHZ
    SD_Error=HAL_SD_Init(&SDCARD_Handler);
    if(SD_Error!=HAL_OK)
    {
        return 1;
    }
	//获取SD卡信息
	HAL_SD_GetCardInfo(&SDCARD_Handler,&SDCardInfo);
    SD_Error=HAL_SD_ConfigWideBusOperation(&SDCARD_Handler,SDIO_BUS_WIDE_4B);//使能宽总线模式
    if(SD_Error!=HAL_OK)
    {
        return 2;
    }
    return 0;
}

void HAL_SD_MspDeInit(SD_HandleTypeDef* hsd)
{
  if(hsd->Instance==SDIO)
  {
  /* USER CODE BEGIN SDIO_MspDeInit 0 */

  /* USER CODE END SDIO_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SDIO_CLK_DISABLE();

    /**SDIO GPIO Configuration
    PC8     ------> SDIO_D0
    PC9     ------> SDIO_D1
    PC10     ------> SDIO_D2
    PC11     ------> SDIO_D3
    PC12     ------> SDIO_CK
    PD2     ------> SDIO_CMD
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
                          |GPIO_PIN_12);

    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);

  /* USER CODE BEGIN SDIO_MspDeInit 1 */

  /* USER CODE END SDIO_MspDeInit 1 */
  }

}
//SDMMC底层驱动，时钟使能，引脚配置，DMA配置
//此函数会被HAL_SD_Init()调用
//hsd:SD卡句柄
void HAL_SD_MspInit(SD_HandleTypeDef *hsd)
{
    DMA_HandleTypeDef TxDMAHandler,RxDMAHandler;
    GPIO_InitTypeDef GPIO_Initure;
    
    __HAL_RCC_SDIO_CLK_ENABLE();    //使能SDIO时钟
    __HAL_RCC_DMA2_CLK_ENABLE();    //使能DMA2时钟 
    __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC时钟
    __HAL_RCC_GPIOD_CLK_ENABLE();   //使能GPIOD时钟
    
    //PC8,9,10,11,12
    GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;      //推挽复用
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    GPIO_Initure.Alternate=GPIO_AF12_SDIO;  //复用为SDIO
    HAL_GPIO_Init(GPIOC,&GPIO_Initure);     //初始化
    
    //PD2
    GPIO_Initure.Pin=GPIO_PIN_2;            
    HAL_GPIO_Init(GPIOD,&GPIO_Initure);     //初始化

#if (SD_DMA_MODE==1)                        //使用DMA模式
    HAL_NVIC_SetPriority(SDMMC1_IRQn,2,0);  //配置SDMMC1中断，抢占优先级2，子优先级0
    HAL_NVIC_EnableIRQ(SDMMC1_IRQn);        //使能SDMMC1中断
    
    //配置发送DMA
    SDRxDMAHandler.Instance=DMA2_Stream3;
    SDRxDMAHandler.Init.Channel=DMA_CHANNEL_4;
    SDRxDMAHandler.Init.Direction=DMA_PERIPH_TO_MEMORY;
    SDRxDMAHandler.Init.PeriphInc=DMA_PINC_DISABLE;
    SDRxDMAHandler.Init.MemInc=DMA_MINC_ENABLE;
    SDRxDMAHandler.Init.PeriphDataAlignment=DMA_PDATAALIGN_WORD;
    SDRxDMAHandler.Init.MemDataAlignment=DMA_MDATAALIGN_WORD;
    SDRxDMAHandler.Init.Mode=DMA_PFCTRL;
    SDRxDMAHandler.Init.Priority=DMA_PRIORITY_VERY_HIGH;
    SDRxDMAHandler.Init.FIFOMode=DMA_FIFOMODE_ENABLE;
    SDRxDMAHandler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;
    SDRxDMAHandler.Init.MemBurst=DMA_MBURST_INC4;
    SDRxDMAHandler.Init.PeriphBurst=DMA_PBURST_INC4;

    __HAL_LINKDMA(hsd, hdmarx, SDRxDMAHandler); //将接收DMA和SD卡的发送DMA连接起来
    HAL_DMA_DeInit(&SDRxDMAHandler);
    HAL_DMA_Init(&SDRxDMAHandler);              //初始化接收DMA
    
    //配置接收DMA 
    SDTxDMAHandler.Instance=DMA2_Stream6;
    SDTxDMAHandler.Init.Channel=DMA_CHANNEL_4;
    SDTxDMAHandler.Init.Direction=DMA_MEMORY_TO_PERIPH;
    SDTxDMAHandler.Init.PeriphInc=DMA_PINC_DISABLE;
    SDTxDMAHandler.Init.MemInc=DMA_MINC_ENABLE;
    SDTxDMAHandler.Init.PeriphDataAlignment=DMA_PDATAALIGN_WORD;
    SDTxDMAHandler.Init.MemDataAlignment=DMA_MDATAALIGN_WORD;
    SDTxDMAHandler.Init.Mode=DMA_PFCTRL;
    SDTxDMAHandler.Init.Priority=DMA_PRIORITY_VERY_HIGH;
    SDTxDMAHandler.Init.FIFOMode=DMA_FIFOMODE_ENABLE;
    SDTxDMAHandler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;
    SDTxDMAHandler.Init.MemBurst=DMA_MBURST_INC4;
    SDTxDMAHandler.Init.PeriphBurst=DMA_PBURST_INC4;
    
    __HAL_LINKDMA(hsd, hdmatx, SDTxDMAHandler);//将发送DMA和SD卡的发送DMA连接起来
    HAL_DMA_DeInit(&SDTxDMAHandler);
    HAL_DMA_Init(&SDTxDMAHandler);              //初始化发送DMA 
  

    HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 3, 0);  //接收DMA中断优先级
    HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
    HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 3, 0);  //发送DMA中断优先级
    HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
#endif
}

//得到卡信息
//cardinfo:卡信息存储区
//返回值:错误状态
unsigned char SD_GetCardInfo(HAL_SD_CardInfoTypeDef *cardinfo)
{
    unsigned char sta;
    sta=HAL_SD_GetCardInfo(&SDCARD_Handler,cardinfo);
    return sta;
}

//判断SD卡是否可以传输(读写)数据
//返回值:SD_TRANSFER_OK 传输完成，可以继续下一次传输
//		 SD_TRANSFER_BUSY SD卡正忙，不可以进行下一次传输
unsigned char SD_GetCardState(void)
{
  return((HAL_SD_GetCardState(&SDCARD_Handler)==HAL_SD_CARD_TRANSFER )?SD_TRANSFER_OK:SD_TRANSFER_BUSY);
}

 #if (SD_DMA_MODE==1)        //DMA模式

//通过DMA读取SD卡一个扇区
//buf:读数据缓存区
//sector:扇区地址
//blocksize:扇区大小(一般都是512字节)
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;
unsigned char SD_ReadBlocks_DMA(uint32_t *buf,uint64_t sector,uint32_t blocksize,uint32_t cnt)
{
    unsigned char err=0;
	unsigned int timeout=SD_TIMEOUT;
	err=HAL_SD_ReadBlocks_DMA(&SDCARD_Handler,(uint8_t*)buf,sector,cnt);//通过DMA读取SD卡n个扇区

	if(err==0)
	{
		//等待SD卡读完
		while(SD_GetCardState()!=SD_TRANSFER_OK)
		{
			if(timeout-- == 0)
			{	
				err=SD_TRANSFER_BUSY;
			}
		} 
	}
    return err;
}

//写SD卡
//buf:写数据缓存区
//sector:扇区地址
//blocksize:扇区大小(一般都是512字节)
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;	
unsigned char SD_WriteBlocks_DMA(uint32_t *buf,uint64_t sector,uint32_t blocksize,uint32_t cnt)
{
    unsigned char err=0; 
	unsigned int timeout=SD_TIMEOUT;
	err=HAL_SD_WriteBlocks_DMA(&SDCARD_Handler,(uint8_t*)buf,sector,cnt);//通过DMA写SD卡n个扇区

	if(err==0)
	{
		//等待SD卡写完
		while(SD_GetCardState()!=SD_TRANSFER_OK)
		{
			if(timeout-- == 0)
			{	
				err=SD_TRANSFER_BUSY;
			}
		} 
	}
    return err;
}

//读SD卡
//buf:读数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;
unsigned char SD_ReadDisk(unsigned char* buf,unsigned int sector,unsigned int cnt)
{
    unsigned char sta=HAL_OK;
    long long lsector=sector;
	unsigned int timeout=SD_TIMEOUT;
    unsigned char n;
	
	sta=SD_ReadBlocks_DMA((uint32_t*)buf,lsector, 512,cnt);
   
    return sta;
}  

//写SD卡
//buf:写数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;	
unsigned char SD_WriteDisk(unsigned char *buf,unsigned int sector,unsigned int cnt)
{   
    unsigned char sta=HAL_OK;
    long long lsector=sector;
	unsigned int timeout=SD_TIMEOUT;
    unsigned char n;

	sta=SD_WriteBlocks_DMA((uint32_t*)buf,lsector,512,cnt);//多个sector的写操作

    return sta;
} 

//SDMMC1中断服务函数
void SDMMC1_IRQHandler(void)
{
    HAL_SD_IRQHandler(&SDCARD_Handler);
}

//DMA2数据流6中断服务函数
void DMA2_Stream6_IRQHandler(void)
{
    HAL_DMA_IRQHandler(SDCARD_Handler.hdmatx);
}

//DMA2数据流3中断服务函数
void DMA2_Stream3_IRQHandler(void)
{
    HAL_DMA_IRQHandler(SDCARD_Handler.hdmarx);
}
#else                                   //轮训模式
 
//读SD卡
//buf:读数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;
unsigned char SD_ReadDisk(unsigned char* buf,unsigned int sector,unsigned int cnt)
{
    unsigned char sta=HAL_OK;
	unsigned int timeout=SD_TIMEOUT;
    long long lsector=sector;
    INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
	sta=HAL_SD_ReadBlocks(&SDCARD_Handler, (uint8_t*)buf,lsector,cnt,SD_TIMEOUT);//多个sector的读操作
	
	//等待SD卡读完
	while(SD_GetCardState()!=SD_TRANSFER_OK)
    {
		if(timeout-- == 0)
		{	
			sta=SD_TRANSFER_BUSY;
		}
    }
    INTX_ENABLE();//开启总中断
    return sta;
}  


//写SD卡
//buf:写数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;	
unsigned char SD_WriteDisk(unsigned char *buf,unsigned int sector,unsigned int cnt)
{   
    unsigned char sta=HAL_OK;
	unsigned int timeout=SD_TIMEOUT;
    long long lsector=sector;
    INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
	sta=HAL_SD_WriteBlocks(&SDCARD_Handler,(uint8_t*)buf,lsector,cnt,SD_TIMEOUT);//多个sector的写操作
		
	//等待SD卡写完
	while(SD_GetCardState()!=SD_TRANSFER_OK)
    {
		if(timeout-- == 0)
		{	
			sta=SD_TRANSFER_BUSY;
		}
    }    
	INTX_ENABLE();//开启总中断
    return sta;
}

//通过串口打印SD卡相关信息
void show_sdcard_info(void)
{
	uint64_t CardCap;	//SD卡容量
	HAL_SD_CardCIDTypeDef SDCard_CID;

	HAL_SD_GetCardCID(&SDCARD_Handler,&SDCard_CID);	//获取CID
	SD_GetCardInfo(&SDCardInfo);					//获取SD卡信息
	switch(SDCardInfo.CardType)
	{
		case CARD_SDSC:
		{
			if(SDCardInfo.CardVersion == CARD_V1_X)
				printf("Card Type:SDSC V1\r\n");
			else if(SDCardInfo.CardVersion == CARD_V2_X)
				printf("Card Type:SDSC V2\r\n");
		}
		break;
		case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
	}	
	CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize);	//计算SD卡容量
  	printf("Card ManufacturerID:%d\r\n",SDCard_CID.ManufacturerID);					//制造商ID
 	printf("Card RCA:%d\r\n",SDCardInfo.RelCardAdd);								//卡相对地址
	printf("LogBlockNbr:%d \r\n",(unsigned int)(SDCardInfo.LogBlockNbr));					//显示逻辑块数量
	printf("LogBlockSize:%d \r\n",(unsigned int)(SDCardInfo.LogBlockSize));					//显示逻辑块大小
	printf("Card Capacity:%d MB\r\n",(unsigned int)(CardCap>>20));							//显示容量
 	printf("Card BlockSize:%d\r\n\r\n",SDCardInfo.BlockSize);						//显示块大小
}

//测试SD卡的读取
//从secaddr地址开始,读取seccnt个扇区的数据
//secaddr:扇区地址
//seccnt:扇区数
void sd_test_read(unsigned int secaddr,unsigned int seccnt)
{
	unsigned int i; unsigned char *buf; unsigned char sta=0;
	buf=malloc(seccnt*512);	//申请内存
	sta=SD_ReadDisk(buf,secaddr,seccnt);//读取secaddr扇区开始的内容
	if(sta==0)						
	{	 
		printf("SECTOR %d DATA:\r\n",secaddr);
		for(i=0;i<seccnt*512;i++)printf("%x ",buf[i]);//打印secaddr开始的扇区数据    	   
		printf("\r\nDATA ENDED\r\n"); 
	}else printf("err:%d\r\n",sta);
	free(buf);	//释放内存	   
}
//测试SD卡的写入(慎用,最好写全是0XFF的扇区,否则可能损坏SD卡.)
//从secaddr地址开始,写入seccnt个扇区的数据
//secaddr:扇区地址
//seccnt:扇区数
void sd_test_write(unsigned int secaddr,unsigned int seccnt)
{
	unsigned int i;
	unsigned char *buf; unsigned char sta=0; 
	buf=malloc(seccnt*512);			//从SDRAM申请内存
	for(i=0;i<seccnt*512;i++) buf[i]=i*3; 		//初始化写入的数据,是3的倍数.
	sta=SD_WriteDisk(buf,secaddr,seccnt);		//从secaddr扇区开始写入seccnt个扇区内容
	if(sta==0) printf("Write over!\r\n");		  
	else printf("err:%d\r\n",sta);
	free(buf);							//释放内存	   
}

int sd_write(unsigned int off_set, const void *buf, int len)
{
    unsigned char ret;
    // block地址
    unsigned int block_num = off_set/512;
    // 旧数据长度
    unsigned int old_len = off_set%512;
    printf("-----write---\n");
    // 申请内存
    // unsigned char *buf_w = (unsigned char *)malloc(512);
    unsigned char buf_w[512];
    if(buf_w == NULL)
    {
        printf("---malloc failed\n");
        return;
    }
    // 当前block足够存放数据
    if(old_len + len <=512)
    {
        printf("---------1--------\n");
        // 读取旧数据
        SD_ReadDisk(buf_w, 0, 1);
        // 复制新数据
        printf("---------11--------\n");
        memcpy(buf_w+old_len, buf, len);
        // 写入新数据+旧数据
        printf("---------12--------\n");
        ret = SD_WriteDisk(buf_w, block_num, 1);
        printf("---------13--------\n");
    }
    else
    {
        printf("---------2--------\n");
        // 读取旧数据
        SD_ReadDisk(buf_w, block_num, 1);
        // 复制新数据
        memcpy(buf_w+old_len, buf, 512-old_len);
        // 写入新数据+旧数据
        ret = SD_WriteDisk(buf_w, block_num, 1);
        // 写入长度
        unsigned int w_len = 512-old_len;
        // 剩余长度
        unsigned int remain_len = len-w_len;     
        unsigned int tmp = remain_len/512;
        for(unsigned int i=0; i<tmp; i++)
        {
            printf("---------%d--------\n", i);
            // 清空数据
            memset(buf_w, 0, 512);
            // 复制数据
            memcpy(buf_w, buf+w_len, 512);
            // 将数据写入
            SD_WriteDisk(buf_w, ++block_num, 1);
            // 修改写入长度
            w_len += 512;
            // 修改剩余长度
            remain_len -= 512;
        }
        // 清空数据
        memset(buf_w, 0, 512);
        // 读取原始数据
        SD_ReadDisk(buf_w, ++block_num, 1);
        // 复制新数据
        memcpy(buf_w, buf+w_len, remain_len);
        // 将新数据+原始数据写入到sd
        ret = SD_WriteDisk(buf_w, block_num, 1);
    }
    printf("--write over---\n");
    return ret;
}

int sd_read(unsigned int off_set, void *buf, int len)
{
    int ret;
    printf("---------read--------\n");
    // block地址
    unsigned int block_num = off_set/512;
    // 申请内存
    unsigned char buf_r[512];
    // 旧数据长度
    unsigned int old_len = off_set%512;
    // 清空缓冲区
    memset(buf_r, 0, 512);
    // 读取数据
    ret = SD_ReadDisk(buf_r, block_num, 1);
    // 剩余数据区足够存储len
    if(old_len + len <= 512)
    {
        // 复制数据
        memcpy(buf, buf_r+old_len, len);
    }
    else
    {
        memcpy(buf, buf_r+old_len, 512-old_len);
        // 已经读取的长度
        unsigned int r_len = 512-old_len;
        // 剩余长度
        unsigned int remain_len = len - r_len;
        unsigned int tmp = remain_len/512;
        for(unsigned int i=0; i<tmp; i++)
        {
            printf("---------%d %d %d--------\n", i, tmp, remain_len);
            // 清空缓冲区
            memset(buf_r, 0, 512);
            printf("-----21------\n");
            // 读取一个block
            SD_ReadDisk(buf_r, 0, 1);
            // 复制数据
            printf("-----22------\n");
            memcpy(buf, buf_r, 512);
            // 更新已读长度
            r_len += 512;
            // 更新剩余长度
            remain_len -= 512;
        }
        // 清空缓冲区
        memset(buf_r, 0, 512);
        // 读取一个block
        printf("-----23------\n");
        ret = SD_ReadDisk(buf_r, ++block_num, 1);
        // 复制数据
        memcpy(buf, buf_r, 512-remain_len);
    }
    printf("---------read over--------\n");
    return ret;
}
#endif
